package Dm

import (
	"db2s/global"
	"db2s/parDef"
	"db2s/ref"
	"errors"
	"fmt"
	"strings"
)

type columnMeta struct {
	DatabaseName  string `json:"databaseName"`
	TableName     string `json:"tableName"`
	ColumnName    string `json:"columnName"`
	ColumnType    string `json:"columnType"` //原始的数据类型，不带长度的
	ColumnSeq     string `json:"columnSeq"`
	IsNull        string `json:"isNull"` //
	Charset       string `json:"charset"`
	CollationName string `json:"collationName"`
	ColumnComment string `json:"columnComment"`
	ColumnDefault string `json:"columnDefault"`
	DataType      string `json:"dataType"` //处理过的数据类型，带长度的
	DataLength    int64  `json:"dataLength"`
	CharLength    int64  `json:"charLength"`
	DataPrecision int64  `json:"dataPrecision"`
	DataScale     int64  `json:"dataScale"`
	Invisible     bool   `json:"invisible"`
	AutoIncrement bool
}

func colMetaMapInit(s columnMeta) parDef.ColMetaMapS {
	return parDef.ColMetaMapS{
		DatabaseName:     s.DatabaseName,
		TableName:        s.TableName,
		ColumnName:       s.ColumnName,
		Charset:          s.Charset,
		CollationName:    s.CollationName,
		ColAutoIncrement: s.AutoIncrement,
		Invisible:        s.Invisible,
		ColumnComment:    s.ColumnComment,
		ColumnSeq:        s.ColumnSeq,
	}
}

func charTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "char"
	switch strings.ToUpper(m.ColumnType) {
	case "CHAR", "CHARACTER", "NCHAR":
		/*
			定义长度: CHAR 类型需要在定义时指定长度,最大长度为 2000 个字符。例如, CHAR(10) 表示最多可以存储 10 个字符的字符串。
			存储空间: CHAR 类型会占用固定的存储空间,即定义的长度个字节。例如, CHAR(10) 类型会占用 10 个字节的存储空间。
		*/
		res.Type.ColTypeMap = fmt.Sprintf("char(show)")
		res.Type.MaxValue = 32767
		res.Type.ShowValue = m.CharLength
		res.Type.UseByte = m.CharLength
	case "VARCHAR", "VARCHAR2", "NVARCHAR2":
		/*
			定义长度: VARCHAR 类型需要在定义时指定最大长度,最大长度为 4000 个字符。例如, VARCHAR2(50) 表示最多可以存储 50 个字符的字符串。
		*/
		res.Type.ColTypeMap = fmt.Sprintf("varchar(show)")
		res.Type.MaxValue = 32767
		res.Type.Variable = true
		res.Type.ShowValue = m.CharLength
		res.Type.UseByte = m.CharLength
	default:
		err = ref.ErrAddPrintf("charTypeMap", errors.New(fmt.Sprintf("type is not match. type is %v", strings.ToUpper(m.ColumnType))))
	}
	return
}

func iSVarchar(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	switch strings.ToUpper(m.ColumnType) {
	case "CHAR", "NCHAR", "CHARACTER", "VARCHAR", "NVARCHAR2", "VARCHAR2":
		res, err = charTypeMap(m, p)
	default:
		err = ref.ErrAddPrintf("iSVarchar", errors.New(fmt.Sprintf("not match type %v", m.DataType)))
	}
	return
}
func ExtractTypeName(s1 string) string {
	var bef, aft string
	if p := strings.Index(s1, "("); p != -1 {
		bef = s1[:p]
	}
	if p := strings.Index(s1, ")"); p != -1 {
		aft = s1[p+1:]
	}
	if len(bef) > 0 || len(aft) > 0 {
		return strings.TrimSpace(fmt.Sprintf("%v%v", bef, aft))
	}
	return s1
}
func intTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	if strings.Contains(strings.ToUpper(m.DataType), "UNSIGNED") {
		res.Type.Symbol = true
	}
	res.TypeBelong = "numerical"
	switch strings.ToUpper(m.ColumnType) {
	case "BIT":
		/*
			BIT 类型用于存储整数数据 1、0 或 NULL，只有 0 才转换为假，其他非空、非 0 值都会自动转换为真，可以用来支持 ODBC 和 JDBC 的布尔数据类型。DM 的 BIT 类型与 SQL SERVER2000 的 BIT 数据类型相似
		*/
		res.TypeBelong = "bit"
		res.Type.MinValue = 1
		res.Type.MaxValue = 1
		res.Type.ShowValue = 0
	case "TINYINT", "BYTE":
		res.Type.MinValue = -128
		res.Type.MaxValue = 127
		res.Type.ShowValue = 127
		res.Type.UseByte = 1
		res.Type.ColTypeMap = "int"
	case "SMALLINT":
		res.Type.MinValue = -32768
		res.Type.MaxValue = 32767
		res.Type.ShowValue = 32767
		res.Type.UseByte = 2
		res.Type.ColTypeMap = "int"
	case "MEDIUMINT":
		res.Type.MinValue = -8388608
		res.Type.MaxValue = 8388607
		res.Type.ShowValue = 8388607
		res.Type.UseByte = 3
		res.Type.ColTypeMap = "int"
	case "INT", "INTEGER", "PLS_INTEGER":
		res.Type.MinValue = -2147483648
		res.Type.MaxValue = 2147483647
		res.Type.ShowValue = 2147483647
		res.Type.UseByte = 4
		res.Type.ColTypeMap = "int"
	case "BIGINT":
		res.Type.MinValue = -9223372036854775808
		res.Type.MaxValue = 9223372036854775807
		res.Type.ShowValue = 9223372036854775807
		res.Type.UseByte = 8
		res.Type.ColTypeMap = "int"
	default:
		err = ref.ErrAddPrintf("intTypeMap", errors.New(fmt.Sprintf("type is not match. type is %v", strings.ToUpper(m.ColumnType))))
	}
	return
}

/*
numberTypeMap

	在 Oracle 中, NUMBER 类型列的 DATA_LENGTH 属性通常为 22。这里有几点需要解释:
	1):数字精度和标度: Oracle 中的 NUMBER 类型可以存储带小数点的数值。NUMBER 类型有两个属性:精度(PRECISION)和标度(SCALE)。精度指数值可以存储的最大位数,标度指小数点后可以存储的位数。
		默认 NUMBER 类型的长度: 当 NUMBER 类型的精度和标度未指定时,Oracle 会默认使用精度 38,标度 0。这种情况下,DATA_LENGTH 属性会被设置为 22 个字节。
		22 个字节的原因:Oracle 内部使用 16 个字节来存储 38 位精度的数值。另外 6 个字节用于存储附加信息,如正负号、小数位数等。所以默认 NUMBER 类型列的 DATA_LENGTH 属性为 22 个字节。
	2): number(p,s)  如何不指定p和s，则默认为number(38,0);即最大38位整数,如何只指定p，则s默认为0，即整数。例如number(10)，表示10位整数,同时指定p和s，则p必须大于等于s，例如number(10,2)，表示最多10位数字，其中包括两位小数
		s可以是负数，表示小数点左边的位数。例如number(10,-2)表示10位整数，且最多保留到百位
*/
func numberTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	//number(p,s)  如何不指定p和s，则默认为number(38,0);即最大38位整数
	//如何只指定p，则s默认为0，即整数。例如number(10)，表示10位整数
	//同时指定p和s，则p必须大于等于s，例如number(10,2)，表示最多10位数字，其中包括两位小数
	//s可以是负数，表示小数点左边的位数。例如number(10,-2)表示10位整数，且最多保留到百位
	res = p
	res.TypeBelong = "decimal"
	res.Type.ColTypeMap = "decimal(precision,scale)"
	switch {
	case m.DataPrecision == 0 && m.DataScale == 0: //不定长整数位 number、number(*,0)、number(*)
		res.Type.Precision = 40
		res.Type.ColTypeMap = "decimal(max,max)"
	case m.DataPrecision > 0 && m.DataScale == 0:
		res.Type.Precision = m.DataPrecision
	case m.DataPrecision == 0 && m.DataScale > 0: //number(*,5)
		res.Type.Precision = 38
		res.Type.Scale = m.DataScale
	case m.DataPrecision > 0 && m.DataScale > 0 && m.DataPrecision < m.DataScale: //number(10,20)
		res.Type.Precision = m.DataPrecision + m.DataScale
		res.Type.Scale = m.DataScale
	case m.DataPrecision == 0 && m.DataScale < 0: //负数开头，表示只有整数，没有小数。例如：number(*,-2)
		res.Type.Precision = 40
	case m.DataPrecision > 0 && m.DataScale > 0: // number(DataPrecision,Scale)
		res.Type.Precision = m.DataPrecision
		res.Type.Scale = m.DataScale
	case m.DataPrecision > 0 && m.DataScale < 0: //负数开头，表示只有整数，没有小数。例如：number(10,-2)
		res.Type.Precision = m.DataPrecision
	default:
		err = ref.ErrAddPrintf("intTypeMap", errors.New(fmt.Sprintf("type is not match. type is %v(%v,%v)", strings.ToUpper(m.ColumnType), m.DataPrecision, m.DataScale)))
	}
	return
}

/*
FloatTypeRedefine
"FLOAT", "BINARY_FLOAT", "BINARY_DOUBLE": //浮点类型
float 是1~126的二进制长度，位数需要转换成十进制precision =(precision * 0.30103) 向上取整"DOUBLE PRECISION"
binary_float，binary_double 只能存17位有效数字
*/
func floatTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "float"
	res.Type.ColTypeMap = "float(precision)"
	switch strings.ToUpper(m.ColumnType) {
	case "FLOAT", "REAL":
		/*
			Oracle 的 FLOAT 数据类型可以表示约 1 到 38 位十进制有效数字的原因如下:
				IEEE 754 标准:
					Oracle 的 FLOAT 数据类型遵循 IEEE 754 浮点数标准。
					根据 IEEE 754 标准, 64 位浮点数包含 1 位符号位、11 位指数位和 52 位尾数位。
				尾数位于有效数字位数的关系:
					52 位尾数位理论上可以表示约 2^52 ≈ 4.5e+15 个不同的值。
					但由于浮点数的内部表示方式,实际上只能表示约 15-16 位十进制有效数字。
				Oracle FLOAT 的特点:
					Oracle 的 FLOAT 数据类型支持 1 到 126 位之间的二进制精度。
					当声明为 FLOAT(53) 时,等同于 IEEE 754 标准中的 64 位 double 类型。
					38 位十进制有效数字的原因:
					虽然 FLOAT(53) 只能表示 15-16 位十进制有效数字,但是 Oracle 的 FLOAT 数据类型支持更高的二进制精度。
					当声明为更高的二进制精度,例如 FLOAT(126),这就可以表示约 38 位十进制有效数字。
					综上所述,Oracle 的 FLOAT 数据类型可以表示约 1 到 38 位十进制有效数字,是因为 Oracle 支持更高的二进制精度,超出了 IEEE 754 标准中 64 位浮点数的限制。但这需要以更高的存储空间为代价。对于大多数场景,使用 FLOAT(53) 即可满足需求。
		*/
		if m.DataPrecision > 0 {
			res.TypeBelong = "float"
			res.Type.MaxValue = 23
			res.Type.ShowValue = int64(float64(m.DataPrecision)*0.30103) + 1
		} else {
			res.TypeBelong = "double"
			res.Type.MaxValue = 53
			res.Type.ShowValue = 53
			res.Type.MaxValue = 53
		}
	case "DOUBLE", "DOUBLE PRECISION":
		res.TypeBelong = "double"
		res.Type.ShowValue = 53
		res.Type.MaxValue = 53
	default:
		err = ref.ErrAddPrintf("floatTypeMap", errors.New(fmt.Sprintf("type is not match. type is %v(%v)", strings.ToUpper(m.ColumnType), m.DataPrecision)))
	}
	return
}

/*
	rowID是一个 18 字节的 CHAR 类型,它由 6 个部分组成:
	数据文件号(1 byte)
	块号(3 bytes)
	行号(2 bytes)
	检查和(2 bytes)

但是oracle使用base 64编码将18字节的rowID值转换为10个ASCII字符，所以实际存储的时候时，将18字节用base 64编码压缩成10字符，所以all_table_column中data_length显示的是10
*/
func rowIdTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "char"
	switch m.ColumnType {
	case "ROWID":
		res.Type.MaxValue = 18
		res.Type.ShowValue = 18
		res.Type.UseByte = 18
		res.Type.ColTypeMap = fmt.Sprintf("char(show)")
	case "BFILE":
		res.Type.MaxValue = 512
		res.Type.ShowValue = 512
		res.Type.UseByte = 512
		res.Type.ColTypeMap = fmt.Sprintf("char(show)")
	default:
		err = ref.ErrAddPrintf("rowIdTypeMap", errors.New(fmt.Sprintf("type is not match. type is %v", strings.ToUpper(m.ColumnType))))
	}
	return
}

/*
Oracle内部以二进制的形式存储DATE数据。
它包含了:century(1个字节)、year(1个字节)、month(1个字节)、day(1个字节)、hour(1个字节)、minute(1个字节)、second(1个字节),共7个字节。
*/
func timeTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "time"
	switch strings.ToUpper(m.ColumnType) {
	case "DATE":
		/*
			DATE 类型:
				存储日期,格式为 YYYY-MM-DD。
				取值范围从 1000-01-01 到 9999-12-31。
				占用 3 个字节的存储空间。
		*/
		res.Type.UseByte = 3
		res.Type.ColTypeMap = "year-month-day"
	case "TIME":
		/*
			TIME 类型:
					存储时间,格式为 HH:MM:SS。
					取值范围从 -838:59:59 到 838:59:59。
					占用 3 个字节的存储空间。
				MySQL 中 TIME(n) 数据类型的 n 最大值是 6。也就是说,MySQL 支持的最大时间值小数精度为 6 位小数。
			具体解释如下:
				TIME(n) 数据类型用于存储时间值,其中 n 表示小数部分的位数。
					当 n 取值为 0 时,时间值精确到秒。
					当 n 取值为 1 到 6 时,时间值精确到小数点后 1 到 6 位。
					n 的最大值为 6，这意味着 TIME(6) 可以存储时间值精确到微秒(百万分之一秒)。
			例如:
					TIME(0) 存储为 'HH:MM:SS'
					TIME(3) 存储为 'HH:MM:SS.sss'
					TIME(6) 存储为 'HH:MM:SS.sssSss'
					需要注意的是,虽然 MySQL 支持 TIME(n) 最大 n 值为 6，但实际使用时根据需要选择合适的精度即可。过高的时间值精度可能会占用更多的存储空间,并且在某些情况下可能无法提供额外的价值。
		*/
		res.Type.UseByte = 3
		switch m.DataPrecision {
		case 0:
			res.Type.ColTypeMap = "hour:minute:second"
		case 1:
			res.Type.ColTypeMap = "hour:minute:second.milli(1)"
		case 2:
			res.Type.ColTypeMap = "hour:minute:second.milli(2)"
		case 3:
			res.Type.ColTypeMap = "hour:minute:second.milli(3)"
		case 4:
			res.Type.ColTypeMap = "hour:minute:second.micro(1)"
		case 5:
			res.Type.ColTypeMap = "hour:minute:second.micro(2)"
		case 6:
			res.Type.ColTypeMap = "hour:minute:second.micro(3)"
		}
	case "DATETIME":
		/*
			DATETIME 类型:
				存储日期和时间,格式为 YYYY-MM-DD HH:MM:SS。
				取值范围从 1000-01-01 00:00:00 到 9999-12-31 23:59:59。
				占用 8 个字节的存储空间。
		*/
		res.Type.UseByte = 8
		switch m.DataPrecision {
		case 0:
			res.Type.ColTypeMap = "year-month-day hour:minute:second"
		case 1:
			res.Type.ColTypeMap = "year-month-day hour:minute:second.milli(1)"
		case 2:
			res.Type.ColTypeMap = "year-month-day hour:minute:second.milli(2)"
		case 3:
			res.Type.ColTypeMap = "year-month-day hour:minute:second.milli(3)"
		case 4:
			res.Type.ColTypeMap = "year-month-day hour:minute:second.micro(1)"
		case 5:
			res.Type.ColTypeMap = "year-month-day hour:minute:second.micro(2)"
		case 6:
			res.Type.ColTypeMap = "year-month-day hour:minute:second.micro(3)"
		}
	}
	return
}
func timestampTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "timestamp"
	switch m.DataScale {
	case 0:
		res.Type.ColTypeMap = "year-month-day hour:minute:second"
	case 1:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.milli(1)"
	case 2:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.milli(2)"
	case 3:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.milli(3)"
	case 4:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.micro(1)"
	case 5:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.micro(2)"
	case 6:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.micro(3)"
	case 7:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.nano(1)"
	case 8:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.nano(2)"
	case 9:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.nano(3)"
	default:
		res.Type.ColTypeMap = "year-month-day hour:minute:second.nano(3)"
	}
	if strings.Contains(m.DataType, "WITH TIME ZONE") || strings.Contains(m.DataType, "WITH LOCAL TIME ZONE") {
		res.Type.ColTypeMap = fmt.Sprintf("%v.utc", res.Type.ColTypeMap)
	}
	return
}
func timeIntervalTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "timeInterval"
	switch strings.ToUpper(m.ColumnType) {
	case "INTERVAL YEAR TO MONTH":
	case "INTERVAL YEAR":
	case "INTERVAL MONTH":
	case "INTERVAL DAY":
	case "INTERVAL DAY TO HOUR":
	case "INTERVAL DAY TO MINUTE":
	case "INTERVAL DAY TO SECOND":
	case "INTERVAL HOUR":
	case "INTERVAL HOUR TO MINUTE":
	case "INTERVAL HOUR TO SECOND":
	case "INTERVAL MINUTE":
	case "INTERVAL MINUTE TO SECOND":
	case "INTERVAL SECOND":
	default:
		err = ref.ErrAddPrintf("rowIdTypeMap", errors.New(fmt.Sprintf("type is not match. type is %v", strings.ToUpper(m.ColumnType))))
	}
	return
}

/*
常用的文本类型转换。

	long {可变长字符列，最大长度限制是2GB，用于不需要作字符串搜索的长串数据，如果要进行字符搜索就要用varchar2类型。long是一种较老的数据类型，将来会逐渐被BLOB、CLOB、NCLOB等大的对象数据类型所取代。}
	blob\clob\nclob {三种大型对象(LOB)，用来保存较大的图形文件或带格式的文本文件，如MiceSoft Word文档，以及音频、视频等非文本文件，最大长度是4GB。LOB有几种类型，取决于你使用的字节的类型，Oracle 8i实实在在地将这些数据存储在数据库内部保存。可以执行读取、存储、写入等特殊操作。}
*/
func textTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "text"
	res.Type.ColTypeMap = "text"
	switch strings.ToUpper(m.ColumnType) {
	case "TEXT", "LONGVARCHAR":
		/*
			LONG 数据类型是 Oracle 数据库中用于存储大文本数据的一种数据类型。最大长度为 2 GB。这意味着它可以存储最多 2 GB 的文本数据。要换算成字符数,需要考虑字符编码。以 UTF-8 编码为例:1 个英文字符占 1 个字节 1 个中文字符占 3 个字节
			需要注意的是, Oracle 不建议再使用 LONG 数据类型,而是建议使用更新的 CLOB 数据类型。CLOB 数据类型的最大长度为 4 GB,比 LONG 类型增加了一倍的容量。同时 CLOB 在性能、可操作性等方面也更加优秀。
		*/
		res.Type.MaxValue = 2147483648
		res.Type.ShowValue = 2147483648
		res.Type.UseByte = 2147483648
	case "CLOB":
		res.Type.MaxValue = 4294967295
		res.Type.ShowValue = 4294967295
		res.Type.UseByte = 4294967295
	default:
		err = ref.ErrAddPrintf("textTypeMap", errors.New(fmt.Sprintf("type is not match. type is %v", strings.ToUpper(m.ColumnType))))
	}
	return
}
func lobTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "lob"
	switch strings.ToUpper(m.ColumnType) {
	case "BLOB":
		res.Type.MaxValue = 4294967296
		res.Type.ShowValue = 4294967296
		res.Type.ColTypeMap = "binary"
		res.Type.UseByte = 4294967296
	case "BINARY":
		res.Type.MaxValue = 32767
		res.Type.ShowValue = m.DataLength
		res.Type.ColTypeMap = "binary(show)"
		res.Type.UseByte = m.DataLength
	case "VARBINARY", "RAW":
		res.Type.MaxValue = 32767
		res.Type.ShowValue = m.DataLength
		res.Type.ColTypeMap = "binary(show)"
		res.Type.UseByte = m.DataLength
	case "IMAGE", "LONGVARBINARY":
		res.Type.MaxValue = 2147483648
		res.Type.ShowValue = 2147483648
		res.Type.ColTypeMap = "binary"
		res.Type.UseByte = 2147483648
	default:
		err = ref.ErrAddPrintf("lobTypeMap", errors.New(fmt.Sprintf("type is not match. type is %v", strings.ToUpper(m.ColumnType))))
	}
	return
}
func gisTypeMap(_ columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	res = p
	res.TypeBelong = "gis"
	res.Type.ColTypeMap = "geometry"
	return
}
func notISVarchar(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	switch strings.ToUpper(m.ColumnType) {
	case "NCHAR", "NVARCHAR2":
		res, err = charTypeMap(m, p)
	case "BIT", "INTEGER", "INT", "PLS_INTEGER", "BIGINT", "TINYINT", "BYTE", "SMALLINT":
		res, err = intTypeMap(m, p)
	case "NUMERIC", "DECIMAL", "DEC", "NUMBER":
		res, err = numberTypeMap(m, p) //case "NUMBER", "DECIMAL", "NUMERIC": //定长数值
	case "FLOAT", "DOUBLE", "REAL", "DOUBLE PRECISION":
		res, err = floatTypeMap(m, p)
	case "ROWID", "BFILE":
		res, err = rowIdTypeMap(m, p)
	case "DATE", "TIME", "DATETIME":
		res, err = timeTypeMap(m, p)
	case "TIMESTAMP", "TIME WITH TIME ZONE", "DATETIME WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE":
		res, err = timestampTypeMap(m, p)
	case "INTERVAL YEAR TO MONTH", "INTERVAL YEAR", "INTERVAL MONTH", "INTERVAL DAY", "INTERVAL DAY TO HOUR", "INTERVAL DAY TO MINUTE", "INTERVAL DAY TO SECOND", "INTERVAL HOUR", "INTERVAL HOUR TO MINUTE", "INTERVAL HOUR TO SECOND", "INTERVAL MINUTE", "INTERVAL MINUTE TO SECOND", "INTERVAL SECOND":
		res, err = timeIntervalTypeMap(m, p)
	case "TEXT", "LONGVARCHAR", "LONG", "CLOB":
		res, err = textTypeMap(m, p)
	case "BINARY", "VARBINARY", "BLOB", "LONG RAW", "RAW", "IMAGE", "LONGVARBINARY": //二进制类型
		res, err = lobTypeMap(m, p)
	case "ST_GEOMETRY", "SDO_GEOMETRY":
		res, err = gisTypeMap(m, p)
	default:
		err = ref.ErrAddPrintf("Oracle.notISVarchar", errors.New(fmt.Sprintf("not match type %v", m.DataType)))
	}
	return
}
func colTypeMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS, err error) {
	//字符串类型包含char，varchar2,nchar,nvarchar2,clob,nclob
	//只有char,nchar,varchar2,nvarchar2涉及到长度
	//char和nchar是定长的，如果输入的字符串长度小于size，则会用空格填充
	//nLob和lob的char_length=0
	if m.CharLength > 0 { //数值类型 和lob类型
		if res, err = iSVarchar(m, p); err != nil {
			err = ref.ErrAddPrintf("colTypeMap", err)
			return
		}
		return
	}
	if res, err = notISVarchar(m, p); err != nil {
		err = ref.ErrAddPrintf("colTypeMap", err)
		return
	}
	return
}
func colNullMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS) {
	//是否允许为null，yes表示为允许，no表示不允许
	res = p
	switch m.IsNull {
	case "Y":
		res.ColNullMap = "YES"
	case "N":
		res.ColNullMap = "NO"
	}
	return
}
func LeftRightSingleQuotationMarks(defaultVal string) (newDefaultVal string) {
	newDefaultVal = defaultVal
	if strings.HasPrefix(defaultVal, "'") && strings.HasSuffix(defaultVal, "'") {
		newDefaultVal = defaultVal[1 : len(defaultVal)-1]
	}
	switch {
	case strings.HasPrefix(defaultVal, "(") && strings.HasSuffix(defaultVal, ")"):
		newDefaultVal = defaultVal[1 : len(defaultVal)-1]
	case !strings.HasPrefix(defaultVal, "(") && strings.Contains(defaultVal, "(") && strings.HasSuffix(defaultVal, ")"):
		if r := strings.Index(defaultVal, "("); r != -1 {
			newDefaultVal = defaultVal[:r]
		}
	default:
		newDefaultVal = defaultVal
	}
	return
}

func colDefaultMap(m columnMeta, p parDef.ColMetaMapS) (res parDef.ColMetaMapS) {
	res = p
	var oldDefaultValue = strings.ToUpper(m.ColumnDefault)
	newDefaultVal := strings.ToUpper(LeftRightSingleQuotationMarks(oldDefaultValue))
	switch {
	case strings.HasPrefix(newDefaultVal, "SYSTIMESTAMP"), strings.HasPrefix(newDefaultVal, "CURRENT_TIMESTAMP"):
		res.ColDefaultMap = "year-month-day hour:minute:second.micro(3).utc"
	case strings.HasPrefix(newDefaultVal, "SYSDATE"):
		switch LeftRightSingleQuotationMarks(strings.ToUpper(m.DataType)) {
		case "DATE":
			res.ColDefaultMap = "year-month-day hour:minute:second"
		case "TIMESTAMP":
			res, _ = timestampTypeMap(m, p)
		case "VARCHAR2":
			res.ColDefaultMap = "year-month-day hour:minute:second"
		default:
			res.ColDefaultMap = "year-month-day hour:minute:second.micro(3)"
		}
	case strings.HasPrefix(newDefaultVal, "TO_CHAR"):
		res.ColDefaultMap = toCharFunc(m.ColumnDefault)
	case strings.HasPrefix(oldDefaultValue, "TO_DATE"):
		res.ColDefaultMap = toDateFunc(m.ColumnDefault)
	case strings.HasPrefix(oldDefaultValue, "TRUNC"):
		res.ColDefaultMap = toTruncFunc()
	case strings.HasPrefix(oldDefaultValue, "SYS_GUID"):
		res.ColDefaultMap = "sys_guid"
	case strings.HasPrefix(oldDefaultValue, "USER"):
		res.ColDefaultMap = "current_user"
	case strings.HasPrefix(oldDefaultValue, "USERENV('SESSIONID')"):
		res.ColDefaultMap = "current_id"
	case strings.HasSuffix(oldDefaultValue, ".NEXTVAL") && strings.HasPrefix(strings.ToLower(m.ColumnType), "number"):
		res.ColAutoIncrement = true
	default:
		p.ColDefaultMap = newDefaultVal
	}
	return
}

func (cm ColumnMe) MetaMap(parameter parDef.Parameter) (result global.Return, err error) {
	if parameter.Meta == nil {
		return
	}
	var colMetaS []columnMeta
	var res []parDef.ColMetaMapS
	for _, v := range parameter.Meta.([]map[string]any) {
		vv := mapNullActive(v)
		if strings.EqualFold(fmt.Sprintf("%v", vv["autoIncrement"]), "NULL") {
			vv["autoIncrement"] = false
		} else {
			vv["autoIncrement"] = true
		}
		var p columnMeta
		if err = ref.MapToStruct(vv, &p); err != nil {
			err = ref.ErrAddPrintf("MetaMap", err)
			return
		}
		colMetaS = append(colMetaS, p)
	}
	for _, v := range colMetaS {
		var p parDef.ColMetaMapS
		if p, err = colTypeMap(v, colMetaMapInit(v)); err != nil {
			err = ref.ErrAddPrintf("MetaMap", err)
			return
		}
		p = colNullMap(v, p)
		p = colDefaultMap(v, p)
		p.ColumnSeq = v.ColumnSeq
		res = append(res, p)
	}
	result.Result = res
	return
}
func metaBaseInit(meta any) (result MetaBaseInitResult, err error) {
	result = MetaBaseInitResult{}
	if result.columnMeta, err = columnMetaBaseInit(meta.(map[string]any)["columnMe"]); err != nil {
		err = ref.ErrAddPrintf("metaBaseInit", err)
		return
	}
	switch meta.(map[string]any)["columnMetaMap"].(type) {
	case []parDef.ColMetaMapS:
		result.columnMetaMap = meta.(map[string]any)["columnMetaMap"].([]parDef.ColMetaMapS)
	}
	switch meta.(map[string]any)["indexMe"].(type) {
	case []parDef.IndexColumnMe:
		result.indexMeta = func() (res []*parDef.IndexColumnMe) {
			for _, v := range meta.(map[string]any)["indexMe"].([]parDef.IndexColumnMe) {
				res = append(res, &v)
			}
			return
		}()
	}
	switch meta.(map[string]any)["partMe"].(type) {
	case parDef.PartMetaData:
		result.partMe = meta.(map[string]any)["partMe"].(parDef.PartMetaData)
	}
	switch meta.(map[string]any)["commentMe"].(type) {
	case string:
		result.Comment = meta.(map[string]any)["commentMe"].(string)
	}
	return
}
func (cm ColumnMe) ColumnAttributeMapClip(parameter parDef.Parameter) (result map[string]parDef.ColMetaMapS, err error) {
	var metaBase MetaBaseInitResult
	if metaBase, err = metaBaseInit(parameter.Meta); err != nil {
		err = ref.ErrAddPrintf("ColumnAttributeMapClip", err)
		return
	}
	result = make(map[string]parDef.ColMetaMapS)
	for _, v := range metaBase.columnMetaMap {
		var key = v.ColumnName
		if _, ok := result[key]; !ok {
			result[key] = v
		}
	}
	return
}
